iT邦幫忙

2023 iThome 鐵人賽

DAY 2
0
自我挑戰組

設計模式系列 第 2

Day2 - 單例模式(Singleton pattern)

  • 分享至 

  • xImage
  •  

什麼是單例模式(Singleton pattern)?

單例確保類別(class)只存在一個實例,且該實例就像全域變數一般,可被同程式的任何人訪問。

解決的問題:

  1. 有些類別只需要初始化及創建一次,並防止後續又被使用者再次創建。
  2. 提供全域訪問

C++範例:

class Singleton
{
public:
    // 使用者透過呼叫GetInstance取得類別的實例
    // 注意此類別的ctor已移至private,防止使用者自行創建實例
    static Singleton *GetInstance()
    {
        // 首次呼叫會創建實體,後續的呼叫則回傳已創建實例的指標
        if (obj == nullptr)
            obj = new Singleton();
        return obj;
    }

    void DoSomething()
    {
        //...
    }

private:
    static Singleton *obj;
    Singleton() {}
};

Singleton *Singleton::obj = nullptr;

// 類別使用方法
int main()
{
    // 呼叫GetInstance獲取實例
    Singleton *instance = Singleton::GetInstance();
    instance->DoSomething();
}

對於多線程程式,上述的Singleton範例並不是thread-safe。假設線程A 通過了上述的if (obj == nullptr),準備要執行obj = new Singleton();,此時若線程B 也剛好通過了if (obj == nullptr),則將會有兩個實例被創建,這不是我們想要的。

對於此問題,Scott Meyers的Effective C++一書提到,可利用local static object在第一次被呼叫使用才初始化的特性來優化:

class Singleton
{
public:
    static Singleton &GetInstance()
    {
        // obj是local static object,在第一次被創建後,之後不
        // 管再進來幾次,都會跳過創建的流程而返回已創建的實例
        static Singleton obj;
        return obj;
    }

    void DoSomething()
    {
        //...
    }

private:
    Singleton();
};

// 類別使用方法
int main()
{
    Singleton &instance = Singleton::GetInstance();
    instance.DoSomething();
}

以上範例在C++11後是保證thread-safe。


上一篇
Day1 - 什麼是設計模式?
下一篇
Day3 - 原型模式(Prototype pattern)
系列文
設計模式30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言